dojo.provide("lorelei.mml.checker");
dojo.require("lorelei.mml.player");

// Lorelei MML Checking Script
// Copyright (c)2008 Logue <http://logue.be/> All rights reserved.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// based on ML.<http://mabimml.modev.jp/mml.js>.

lorelei.mml.checker = {
	meta : {
		"@prefix": "<http://purl.org/net/ns/doas#>",
		"@about": "<http://mabinogi.logue.be/js/lorelei/mml/checker.js>", a: ":JavaScript",
		title: "Lorelei MML Checking Script",
		shortdesc: "Lorelei MML Checking Script.",
		created: "2008-06-05", release: {revision: "1.7.5", created: "2008-10-05"},
		author: {name: "Logue", homepage: "<http://logue.be/>"},
		license: "<http://www.gnu.org/licenses/gpl-3.0.html>",
		acknowledgement: {name: "ML", 'homepage': "<http://mabimml.modev.jp/>" },
		dependencies: "dojo.js"
	},
	noteRevTable : ['c','c+','d','d+','e','f','f+','g','g+','a','a+','b'],
	noteTable : {'c':0,'d':2,'e':4,'f':5,'g':7,'a':9,'b':11},
	init : function(){
		this.inst = dijit.byId('instrument').value;

		// フォームセレクタ
		dojo.query('input[type=radio][name=track]').connect('onclick',function(radio) {
			dojo.byId(radio.target.value).focus();
		});
		// MML記入部
		dojo.query('textarea.mml').connect('onBlur',function(){	// フォームからマウスが離れた時に文字数チェック
			lorelei.mml.checker.check_rank();
		});
		dojo.query('textarea.mml').connect('onKeyDown',function(){
			lorelei.mml.checker.check_rank();
		});
		dojo.query('textarea.mml').connect('onKeyUp',function(){
			lorelei.mml.checker.check_rank();
		});
		dojo.query('textarea.mml').connect('onfocus',function(elem){
			var track_id = elem.target.id + '_radio';
			dijit.byId(track_id).attr('checked',true);	// MMLのチャンネルに対応するラジオボタンをチェック
		});

		// 楽器セレクタ
		dojo.connect(dijit.byId('instrument'),'onChange',function (){
			lorelei.mml.checker.change_inst(this.value);
			lorelei.mml.player.changed = true;
		});

		if (dojo.byId('tone_checker')){
			// MML音域チェックボタン
			dojo.connect(dojo.byId('tone_checker'),'onclick',function (){
				lorelei.mml.checker.check_tone();
			});
		}else{
			console.error('Tone Checker is not defined.');
		}

		if (dojo.byId('Clear')){
			// 全削除ボタン
			dojo.connect(dojo.byId('Clear'),'onclick',function (){
				if( window.confirm(message['delete']) == true){
					dojo.byId('ch1').value = '';
					dojo.byId('ch2').value = '';
					dojo.byId('ch3').value = '';
					lorelei.mml.checker.status();
					dojo.byId('rank_id').value = '-';
					try{
						var appState = new ApplicationState(dojo.byId('ch1').value, dojo.byId('ch2').value, dojo.byId('ch3').value);
						dojo.back.addToHistory(appState);
					}catch(e){
						//null
					}
				}
			});
		}else{
			console.error('Tone Checker is not defined.');
		}

		if (dojo.byId('MmlPaste')){
			// MMLペーストボタン
			dojo.connect(dojo.byId('MmlPaste'),'onclick',function (){
				if(dojo.byId('Mml').value.match( /MML@\s*([\s0-9a-glnortvA-GLNORTV#<>.&+-]*),\s*([\s0-9a-glnortvA-GLNORTV#<>.&+-]*),\s*([\s0-9a-glnortvA-GLNORTV#<>.&+-]*);/ )) {
					buf = [RegExp.$1, RegExp.$2, RegExp.$3].sort(function(a,b){return b.replace(/\s+/g,"").length - a.replace(/\s+/g,"").length});
					dojo.byId('ch1').value = buf[0];
					dojo.byId('ch2').value = buf[1];
					dojo.byId('ch3').value = buf[2];
					try{
						var appState = new ApplicationState(dojo.byId('ch1').value, dojo.byId('ch2').value, dojo.byId('ch3').value);
						dojo.back.addToHistory(appState);
					}catch(e){
						//null
					}
					dojo.byId('Mml').value = '';
					lorelei.mml.checker.check_rank();
				}else{
					alert(message['unknown_format']);
				}
			});
		}else{
			console.error('Tone Checker is not defined.');
		}
/*
		// MML再生ボタン
		dojo.connect(dojo.byId('MmlPlay'),'onclick',function (){
			lorelei.mml.player.mmls = lorelei.mml.checker.getMML();
			lorelei.mml.player.inst = lorelei.mml.checker.inst;
		});
*/
		// MML削除ボタン
		dojo.connect(dojo.byId('MmlClear'),'onclick',function (){
			if( window.confirm(message['delete']) == true) dojo.byId('Mml').value = '';
		});

		// MabiMML形式でクリップボードにコピー
		dojo.connect(dojo.byId('Copy'),'onclick',function (){
			this.disabled = true;
			if( window.confirm(message['clipboard']) == true){
				dojo.require("lorelei.setClipboard");
				var buf = lorelei.mml.checker.getMML();
				lorelei.setClipboard('MML@' + buf[0] + ',' + buf[1] + ',' + buf[2] + ';');
			}
			this.disabled = false;
		});

		lorelei.mml.player.PlayButton = dijit.byId('MmlPlay');	// ボタンの定義
		lorelei.mml.player.StopButton = dijit.byId('MmlStop');
		if(dojo.byId('PlayType')) lorelei.mml.player.Selector = dojo.byId('PlayType').value;
		lorelei.mml.player.Container = dojo.byId('media');
		lorelei.mml.player.init();
	},
	change_inst : function(value){
		console.log('instrument changed',this.value);
		if(this.value <= 8) {
			this.status();
			dojo.byId('tone_checker').disabled = false;
		}else{
			this.status('unknown');
			dojo.byId('tone_checker').disabled = true;
		}
		this.inst = value;
	},
	getMML : function(){	// MMLを配列に入れる
		var mml = dojo.query('textarea.mml');
		var buf =[];
		for (var i=0; i < mml.length; i++){
			buf[i] = mml[i].value.replace(/[^0-9a-glnortvA-GLNORTV#<>.,&+-]/g,"");
		}
		return buf;
	},
	check_rank: function(){	// ランクチェック
		var buf = this.getMML();
		var ranks = [	// ランクと文字数の定義
			[ "-", 200, 100, 0 ],
			[ "F", 400, 200, 100 ],
			[ "E", 500, 200, 100 ],
			[ "D", 600, 250, 150 ],
			[ "C", 650, 250, 200 ],
			[ "B", 700, 300, 200 ],
			[ "A", 750, 300, 200 ],
			[ "9", 800, 350, 200 ],
			[ "8", 850, 400, 200 ],
			[ "7", 900, 400, 200 ],
			[ "6", 950, 450, 200 ],
			[ "5", 1000, 500, 250 ],
			[ "4", 1050, 550, 300 ],
			[ "3", 1100, 600, 350 ],
			[ "2", 1150, 700, 400 ],
			[ "1", 1200, 800, 500 ]
		];

		for(var i = 0; i < ranks.length; i++){
			var r = ranks[i];
			if(r[1] >= buf[0].length && r[2] >= buf[1].length && r[3] >= buf[2].length){
				dojo.byId('rank_id').value = r[0];
				this.rank = i+1;
				break;
			}else{
				dojo.byId('rank_id').value = '0';
			}
		}
		dojo.byId('ch1_length').value = buf[0].length;
		dojo.byId('ch2_length').value = buf[1].length;
		dojo.byId('ch3_length').value = buf[2].length;
		lorelei.mml.player.changed = true;
		this.status();
		
	},
	check_tone: function(){	// 音域チェック
		this.status('loading');
		var buf = this.getMML();
		
		dojo.byId('tone_checker').disabled = true;
		var note_max = 0;
		var note_min = 119;

		for(var partid = 0; partid < buf.length; partid++) {
			var cOctave = 4;
			var mml_notes = buf[partid].match(/[abcdefgnoABCDEFGNO<>][\+\#-]?[0-9]*/g);
			if (mml_notes == null) { continue; }
			for(var mnid=0; mnid < mml_notes.length; mnid++) {
				var mml_note = mml_notes[mnid];
				if(mml_note.match(/[oO](0|[1-9][0-9]*)/)) {
					// オクターブ命令を抽出
					cOctave = parseInt(RegExp.$1);
				} else if(mml_note.match(/</)) {
					// 簡易オクターブ命令を抽出
					cOctave = cOctave-1;
				} else if(mml_note.match(/>/)) {
					cOctave = cOctave+1;
				} else if(mml_note.match(/[nN](0|[1-9][0-9]*)/)) {
					// ノート指定だった場合、その値が音階の値になる
					var note = parseInt(RegExp.$1);
					note_max = (note_max < note)? note: note_max;
					note_min = (note_min > note)? note: note_min;
				} else if(mml_note.match(/([abcdefgABCDEFG])([\+\#-]?)/)) {
					// 通常のノート指定。+と-で音階が変化するため。
					var note = 12*cOctave + this.noteTable[RegExp.$1.toLowerCase()];
					if(RegExp.$2 == '+' || RegExp.$2 == '#') {
						note += 1;
					} else if(RegExp.$2 == '-') {
						note -= 1;
					}
					note_max = (note_max < note)? note: note_max;
					note_min = (note_min > note)? note: note_min;
				}
			}
		}

		note_max = (note_max > 119)? 119: note_max;
		note_min = (note_min < 0)? 0: note_min;
		var tone_result = (note_max<note_min)?"":[
			"O", Math.floor(note_min/12), this.noteRevTable[note_min%12], "-",
			"O", Math.floor(note_max/12), this.noteRevTable[note_max%12]
		].join("");

		console.log('result:',tone_result);

		var parent = this;
		dojo.xhrGet({
			url:		"/instruments/json/" + dijit.byId('instrument').value,
			handleAs:	"json",
			timeout:	5000, // Time in milliseconds
			load:
			function(response, ioArgs) {
				res = response[0].Instrument;
				if (res.isDram == 0) {
					if(res.minNote <= note_min && res.maxNote >= note_max){
						parent.status('ok');
					} else {
						parent.status('no');
					}
				}else{
					parent.status('unknown');
				}
				return response;
			},
			error: function(response, ioArgs) {
				console.error("HTTP status code: ", ioArgs.xhr.status);
				parent.status('unknown');
				return response;
			}
		});
	},
	status : function(type){	// 音域チェック用のアイコン
		var icon_url = "/img/icons/16x16/";
		var image;
		switch (type) {
			case 'ok' :
				image = icon_url+'ok.png';
			break;
			case 'loading' :
				image = icon_url+'ajax-loader.gif';
			break;
			case 'no' :
				image = icon_url+'no.png';
			break;
			case 'unknown':
				image = icon_url+'status_unknown.png';
			break;
			default:
				image = icon_url+'spellcheck.png';
			break;
		}
		dojo.byId('tone_checker').disabled = false;
		dojo.byId('tone_checker').style.backgroundImage = 'url("'+image+'")';
	}
};

console.log(lorelei.mml.checker.meta.title,lorelei.mml.checker.meta.release,' has been loaded!');

dojo.addOnLoad(function (){
	if (dojo.byId('media')) dojo.byId('media').innerHTML = '<img src="' + dojo.moduleUrl("lorelei", "resource/loading_bar.gif") + '" />';
	lorelei.mml.checker.init();
	if (dojo.byId('media')) dojo.byId('media').innerHTML = '';
});

// メモリーリーク対策
dojo.addOnUnload(function(){
	if (dojo.byId('media')) dojo.byId('media').innerHTML = '<img src="' + dojo.moduleUrl("lorelei", "resource/loading_bar.gif") + '" />';
});